package com.danke.lib.banner.widget.banner;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;

import com.danke.lib.banner.R;
import com.danke.lib.banner.widget.helper.BannerRoundCornerHelper;
import com.danke.lib.banner.widget.loopviewpager.BannerFixedSpeedScroller;
import com.danke.lib.banner.widget.loopviewpager.BannerLoopViewPager;
import com.danke.lib.banner.widget.loopviewpager.BannerViewPager;

import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import androidx.annotation.NonNull;
import androidx.viewpager.widget.PagerAdapter;
import androidx.viewpager.widget.ViewPager;

@SuppressWarnings("unchecked")
public abstract class BaseBanner<E, T extends BaseBanner<E, T>> extends RelativeLayout {
    /**
     * 日志
     */
    private static final String TAG = BaseBanner.class.getSimpleName();
    /**
     * 上下文
     */
    protected Context mContext;
    /**
     * ViewPager
     */
    protected BannerViewPager mViewPager;
    /**
     * 数据源
     */
    private List<E> mDatas = new ArrayList<>();
    /**
     * 当前position
     */
    protected int mCurrentPosition;
    /**
     * 上一个position
     */
    protected int mLastPosition;
    /**
     * 高/宽
     */
    private float mScale;
    /**
     * 多久后开始滚动
     */
    private long mDelay;
    /**
     * 滚动间隔
     */
    private long mPeriod;
    /**
     * 是否自动滚动
     */
    private boolean mIsAutoScrollEnable;
    /**
     * 是否显示指示器
     */
    private boolean mIsIndicatorShow;
    /**
     * 是否正在自动滚动中
     */
    private boolean mIsAutoScrolling;
    /**
     * banner间距，主要针对屏幕左右有间距的场景
     */
    private int mBannerGap;
    /**
     * 切换动画
     */
    private Class<? extends ViewPager.PageTransformer> mTransformerClass;

    /**
     * 最后一条item是否显示indicator
     */
    private boolean mIsIndicatorShowWhenLast;

    /**
     * indicator是否below of banner viewpager
     */
    private boolean mIsIndicatorBelowOfBannerItems;

    /**
     * 指示器的的直接容器
     */
    private LinearLayout mLlIndicatorContainer;

    private BannerRoundCornerHelper mRoundCornerHelper;

    /**
     * 设备密度
     */
    protected DisplayMetrics mDisplayMetrics;

    public BaseBanner(Context context) {
        this(context, null, 0);
    }

    public BaseBanner(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public BaseBanner(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        this.mContext = context;
        mDisplayMetrics = context.getResources().getDisplayMetrics();

        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.BaseBanner);
        mScale = ta.getFloat(R.styleable.BaseBanner_bb_scale, -1);

        boolean isLoopEnable = ta.getBoolean(R.styleable.BaseBanner_bb_isLoopEnable, true);
        mDelay = ta.getInt(R.styleable.BaseBanner_bb_delay, 4);
        mPeriod = ta.getInt(R.styleable.BaseBanner_bb_period, 4);
        mIsAutoScrollEnable = ta.getBoolean(R.styleable.BaseBanner_bb_isAutoScrollEnable, true);
        mBannerGap = ta.getDimensionPixelSize(R.styleable.BaseBanner_bb_bannerGap, 0);
        int roundCorner = ta.getDimensionPixelSize(R.styleable.BaseBanner_bb_roundCorner, 0);
        int roundCornerTopLeft = ta.getDimensionPixelSize(
                R.styleable.BaseBanner_bb_roundCornerTopLeft, roundCorner);
        int roundCornerTopRight = ta.getDimensionPixelSize(
                R.styleable.BaseBanner_bb_roundCornerTopRight, roundCorner);
        int roundCornerBottomLeft = ta.getDimensionPixelSize(
                R.styleable.BaseBanner_bb_roundCornerBottomLeft, roundCorner);
        int roundCornerBottomRight = ta.getDimensionPixelSize(
                R.styleable.BaseBanner_bb_roundCornerBottomRight, roundCorner);
        mRoundCornerHelper = new BannerRoundCornerHelper();
        mRoundCornerHelper.setRoundCorner(roundCornerTopLeft, roundCornerTopRight, roundCornerBottomLeft, roundCornerBottomRight);

        mIsIndicatorShow = ta.getBoolean(R.styleable.BaseBanner_bb_isIndicatorShow, true);
        mIsIndicatorShowWhenLast = ta.getBoolean(R.styleable.BaseBanner_bb_isIndicatorShowWhenLast, true);
        mIsIndicatorBelowOfBannerItems = ta.getBoolean(R.styleable.BaseBanner_bb_isIndicatorBelowOfBannerItems, false);
        int indicatorGravity = ta.getInt(R.styleable.BaseBanner_bb_indicatorGravity, Gravity.CENTER);
        float indicatorPaddingStart = ta.getDimension(R.styleable.BaseBanner_bb_indicatorPaddingStart, dp2px(10));
        float indicatorPaddingTop = ta.getDimension(R.styleable.BaseBanner_bb_indicatorPaddingTop, dp2px(6));
        float indicatorPaddingEnd = ta.getDimension(R.styleable.BaseBanner_bb_indicatorPaddingEnd, dp2px(10));
        float indicatorPaddingBottom = ta.getDimension(R.styleable.BaseBanner_bb_indicatorPaddingBottom, dp2px(6));
        ta.recycle();

        //create ViewPager
        mViewPager = isLoopEnable ? new BannerLoopViewPager(context) : new BannerViewPager(context);
        if (isLoopEnable) {
            setScrollSpeed();
        }
        mViewPager.setClipToPadding(false);
        mViewPager.setClipChildren(false);
        mViewPager.setScale(mScale);
        LayoutParams lpViewPager = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
        lpViewPager.addRule(RelativeLayout.CENTER_HORIZONTAL, RelativeLayout.TRUE);
        mViewPager.setId(R.id.id_bannerViewPager);
        addView(mViewPager, lpViewPager);

        //container of indicators
        mLlIndicatorContainer = new LinearLayout(context);
        LayoutParams lpIndicator = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
        if (mIsIndicatorBelowOfBannerItems) {
            lpIndicator.addRule(RelativeLayout.BELOW, R.id.id_bannerViewPager);
        } else {
            lpIndicator.addRule(RelativeLayout.ALIGN_BOTTOM, R.id.id_bannerViewPager);
        }
        mLlIndicatorContainer.setPadding((int) indicatorPaddingStart, (int) indicatorPaddingTop,
                (int) indicatorPaddingEnd, (int) indicatorPaddingBottom);
        mLlIndicatorContainer.setGravity(indicatorGravity);
        mLlIndicatorContainer.setClipChildren(false);
        mLlIndicatorContainer.setClipToPadding(false);
        addView(mLlIndicatorContainer, lpIndicator);

    }

    /**
     * 创建ViewPager的Item布局
     */
    public abstract View onCreateItemView(int position);

    /**
     * 创建显示器
     */
    public abstract View onCreateIndicator();

    /**
     * 设置当前显示器的状态,选中或者未选中
     */
    public abstract void setCurrentIndicator(int position);

    /**
     * 设置数据源
     */
    public T setSource(List<E> list) {
        if (list != null && !list.isEmpty()) {
            this.mDatas.clear();
            this.mDatas.addAll(list);
            setIndicatorShow(mIsIndicatorShow && mDatas.size() > 1);
        }
        return (T) this;
    }

    /**
     * 高/宽
     */
    public T setScale(float scale) {
        this.mScale = scale;
        return (T) this;
    }

    /**
     * 滚动延时,默认5秒
     */
    public T setDelay(long delay) {
        this.mDelay = delay;
        return (T) this;
    }

    /**
     * 滚动间隔,默认5秒
     */
    public T setPeriod(long period) {
        this.mPeriod = period;
        return (T) this;
    }

    /**
     * 设置是否支持自动滚动,默认true.仅对LoopViewPager有效
     */
    public T setAutoScrollEnable(boolean isAutoScrollEnable) {
        this.mIsAutoScrollEnable = isAutoScrollEnable;
        return (T) this;
    }

    /**
     * 设置banner间距,单位dp
     */
    public T setBannerGap(float bannerGapDP) {
        this.mBannerGap = dp2px(bannerGapDP);
        return (T) this;
    }

    /**
     * 设置页面切换动画
     */
    public T setTransformerClass(Class<? extends ViewPager.PageTransformer> transformerClass) {
        this.mTransformerClass = transformerClass;
        return (T) this;
    }

    /**
     * 设置最后一条item是否显示背景条,默认true
     */
    public T setIndicatorShowWhenLast(boolean isIndicatorShowWhenLast) {
        this.mIsIndicatorShowWhenLast = isIndicatorShowWhenLast;
        return (T) this;
    }

    /**
     * 设置底部背景条padding,单位dp
     */
    public T indicatorPadding(float left, float top, float right, float bottom) {
        mLlIndicatorContainer.setPadding(dp2px(left), dp2px(top), dp2px(right), dp2px(bottom));
        return (T) this;
    }

    /**
     * 设置是否显示显示器,默认true
     */
    public T setIndicatorShow(boolean isIndicatorShow) {
        this.mIsIndicatorShow = isIndicatorShow;
        mLlIndicatorContainer.setVisibility(isIndicatorShow ? View.VISIBLE : View.GONE);
        return (T) this;
    }

    /**
     * 指示器显示位置
     *
     * @param gravity See {@link android.view.Gravity}
     */
    public T setIndicatorGravity(int gravity) {
        mLlIndicatorContainer.setGravity(gravity);
        return (T) this;
    }

    public boolean isAutoScrollEnable() {
        return mIsAutoScrollEnable;
    }

    public List<E> getData() {
        return Collections.unmodifiableList(mDatas);
    }

    /**
     * 滚动到下一个item，方便内部类handler调用
     */
    private void scrollToNextItem() {
        scrollToNextItem(mCurrentPosition);
    }

    /**
     * 滚动到下一个item
     */
    private void scrollToNextItem(int position) {
        position++;
        mViewPager.setCurrentItem(position);
    }

    /**
     * 设置viewpager
     */
    private void setViewPager() {
        mViewPager.setScale(mScale);
        if (mBannerGap > 0) {
            mViewPager.setPageMargin(mBannerGap);
        }
        if (mInternalPageListener != null) {
            // RecyclerView中滚动时，如果已设置监听，先移除
            mViewPager.removeOnPageChangeListener(mInternalPageListener);
//            mViewPager.addOnPageChangeListener(mInternalPageListener); // 在setAdapter之后设置
        }
//        Log.d(TAG, "currentPosition1=" + mCurrentPosition);
        InnerBannerAdapter mInnerAdapter = new InnerBannerAdapter();
        mViewPager.setAdapter(mInnerAdapter);
        mViewPager.setOffscreenPageLimit(mDatas.size());
//        Log.d(TAG, "currentPosition2=" + mCurrentPosition);
        if (mInternalPageListener != null) {
            // 在setAdapter之后设置，避免在RecyclerView中滚动时mCurrentPosition错乱
            mViewPager.addOnPageChangeListener(mInternalPageListener);
        }

        if (mTransformerClass != null) {
            try {
                mViewPager.setPageTransformer(true, mTransformerClass.newInstance());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        mViewPager.setCurrentItem(mCurrentPosition);
//        mViewPager.requestLayout();
    }

    private ViewPager.OnPageChangeListener mInternalPageListener = new ViewPager.OnPageChangeListener() {
        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
            if (mOnPageChangeListener != null) {
                mOnPageChangeListener.onPageScrolled(position, positionOffset, positionOffsetPixels);
            }
        }

        @Override
        public void onPageSelected(int position) {
            if (!mDatas.isEmpty()) {
                mCurrentPosition = position % mDatas.size();
            }

            if (mIsIndicatorShow) {
                if (mCurrentPosition == mDatas.size() - 1 && !mIsIndicatorShowWhenLast) {
                    mLlIndicatorContainer.setVisibility(GONE);
                } else {
                    mLlIndicatorContainer.setVisibility(VISIBLE);
                    setCurrentIndicator(mCurrentPosition);
                }
            }

            mLastPosition = mCurrentPosition;
            if (mOnPageChangeListener != null) {
                mOnPageChangeListener.onPageSelected(position);
            }
        }

        @Override
        public void onPageScrollStateChanged(int state) {
            if (mOnPageChangeListener != null) {
                mOnPageChangeListener.onPageScrollStateChanged(state);
            }
        }
    };

    /**
     * 开始滚动
     */
    public void startScroll() {
        startScroll(0);
    }

    /**
     * 开始滚动
     */
    public void startScroll(int fromPosition) {
        if (mDatas == null) {
            throw new IllegalStateException(this.getClass().getSimpleName() + "---> Data source is empty, you must setSource() before startScroll()");
        }
        mCurrentPosition = fromPosition;
        if (mCurrentPosition < 0) {
            mCurrentPosition = 0;
        }
        if (mDatas.size() > 0 && mCurrentPosition > mDatas.size() - 1) {
            mCurrentPosition = 0;
        }
        mLastPosition = mCurrentPosition;

        setViewPager();
        //create indicator
        View indicatorViews = onCreateIndicator();
        if (indicatorViews != null) {
            mLlIndicatorContainer.removeAllViews();
            mLlIndicatorContainer.addView(indicatorViews);
        }

        goOnScroll();
    }

    private BannerHandler mHandler;

    private static class BannerHandler extends Handler {

        static final int MSG_SCROLL_GOON = 10; // 滚动
        static final int MSG_SCROLL_PAUSE = 11; // 暂停

        private WeakReference<BaseBanner> mRef;

        BannerHandler(BaseBanner baseBanner) {
            this.mRef = new WeakReference<>(baseBanner);
        }

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            BaseBanner baseBanner = mRef.get();
            if (baseBanner != null) {
                int what = msg.what;
                switch (what) {
                    case MSG_SCROLL_GOON: { // 滚动
                        baseBanner.scrollToNextItem();
                        sendEmptyMessageDelayed(MSG_SCROLL_GOON, baseBanner.mPeriod * 1000);
                        break;
                    }
                    case MSG_SCROLL_PAUSE: { // 暂停
                        removeCallbacksAndMessages(null);
                        break;
                    }
                }
            }
        }
    }

    /**
     * 继续滚动(for LoopViewPager)
     */
    public void goOnScroll() {
        if (!isValid()) {
            return;
        }

        if (mIsAutoScrolling) {
            return;
        }
        // 只有一条数据时不自动滚动
        if (isLoopViewPager() && mIsAutoScrollEnable && mDatas.size() > 1) {
            pauseScroll();
            if (mHandler == null) {
                mHandler = new BannerHandler(this);
            }
            mHandler.sendEmptyMessageDelayed(BannerHandler.MSG_SCROLL_GOON, mDelay * 1000);
            mIsAutoScrolling = true;
            Log.d(TAG, this.getClass().getSimpleName() + "---> goOnScroll()");
        } else {
            mIsAutoScrolling = false;
        }
    }

    /**
     * 停止滚动(for LoopViewPager)
     */
    public void pauseScroll() {
        if (mHandler != null) {
            mHandler.removeCallbacksAndMessages(null);
        }
        Log.d(TAG, this.getClass().getSimpleName() + "---> pauseScroll()");

        mIsAutoScrolling = false;
    }

    /**
     * 获取ViewPager对象
     */
    public ViewPager getViewPager() {
        return mViewPager;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        if (mRoundCornerHelper.hasCorner()) {
            mRoundCornerHelper.onSizeChanged(this, w, h);
        }
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        if (mRoundCornerHelper.hasCorner()) {
            canvas.saveLayer(mRoundCornerHelper.layer, null, Canvas.ALL_SAVE_FLAG);
            super.dispatchDraw(canvas);
            mRoundCornerHelper.onClipDraw(canvas);
            canvas.restore();
        } else {
            super.dispatchDraw(canvas);
        }
    }

    @Override
    public void draw(Canvas canvas) {
        if (mRoundCornerHelper.hasCorner()) {
            canvas.save();
            canvas.clipPath(mRoundCornerHelper.clipPath);
            super.draw(canvas);
            canvas.restore();
        } else {
            super.draw(canvas);
        }
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        int action = ev.getAction();
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                pauseScroll();
                break;
            case MotionEvent.ACTION_UP:
                goOnScroll();
                break;
            case MotionEvent.ACTION_CANCEL:
                goOnScroll();
                break;

        }
        return super.dispatchTouchEvent(ev);
    }

//    @Override
//    protected void onWindowVisibilityChanged(int visibility) {
//        super.onWindowVisibilityChanged(visibility);
//        Log.d(TAG, "onWindowVisibilityChanged: " + visibility);
//    }

    /**
     * 大部分App首页MainActivity底部会有几个tab，切换tab时切换Fragment，
     * 实测发现切换tab时onWindowVisibilityChanged不执行，onVisibilityChanged会执行
     */
    @Override
    protected void onVisibilityChanged(@NonNull View changedView, int visibility) {
        super.onVisibilityChanged(changedView, visibility);
        Log.d(TAG, this.getClass().getSimpleName() + "---> onVisibilityChanged: " + visibility);
        try {
            if (visibility == VISIBLE) {
                if (mIsAutoScrollEnable) {
                    goOnScroll();
                }
            } else {
                pauseScroll();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        // 当banner属于RecycleView的item时，滑出屏幕会执行detach此时需要暂停轮播
        pauseScroll();
        if (mOnStateChangedListener != null) {
            mOnStateChangedListener.onDetachedFromWindow(mCurrentPosition);
        }
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
    }

    private class InnerBannerAdapter extends PagerAdapter {
        @Override
        public int getCount() {
            return mDatas.size();
        }

        @NonNull
        @Override
        public Object instantiateItem(ViewGroup container, final int position) {
            View inflate = onCreateItemView(position);
            inflate.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (mOnItemClickL != null) {
                        mOnItemClickL.onItemClick(position);
                    }
                }
            });
            container.addView(inflate);

            return inflate;
        }

        @Override
        public void destroyItem(ViewGroup container, int position, @NonNull Object object) {
            container.removeView((View) object);
        }

        @Override
        public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
            return view == object;
        }

        public int getItemPosition(@NonNull Object object) {
            return POSITION_NONE;
        }
    }

    /**
     * 设置滚动速率
     */
    private void setScrollSpeed() {
        try {
            Field mScroller = ViewPager.class.getDeclaredField("mScroller");
            mScroller.setAccessible(true);
            AccelerateDecelerateInterpolator interpolator = new AccelerateDecelerateInterpolator();
            BannerFixedSpeedScroller myScroller = new BannerFixedSpeedScroller(mContext, interpolator, 450);
            mScroller.set(mViewPager, myScroller);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    protected int dp2px(float dp) {
        float scale = mContext.getResources().getDisplayMetrics().density;
        return (int) (dp * scale + 0.5F);
    }

    private float sp2px(float sp) {
        final float scale = mContext.getResources().getDisplayMetrics().scaledDensity;
        return sp * scale;
    }

    protected boolean isLoopViewPager() {
        return mViewPager instanceof BannerLoopViewPager;
    }

    protected boolean isValid() {
        if (mViewPager == null) {
            Log.e(TAG, "ViewPager is not exist!");
            return false;
        }

        if (mDatas.isEmpty()) {
            Log.e(TAG, this.getClass().getSimpleName() + "---> DataList must be not empty!");
            return false;
        }

        return true;
    }

    //listener
    private ViewPager.OnPageChangeListener mOnPageChangeListener;

    public void addOnPageChangeListener(ViewPager.OnPageChangeListener listener) {
        mOnPageChangeListener = listener;
    }

    private OnItemClickL mOnItemClickL;

    public void setOnItemClickL(OnItemClickL onItemClickL) {
        this.mOnItemClickL = onItemClickL;
    }

    public interface OnItemClickL {
        void onItemClick(int position);
    }

    // 状态变化监听
    private OnStateChangedListener mOnStateChangedListener;

    public void setOnStateChangedListener(OnStateChangedListener onStateChangedListener) {
        this.mOnStateChangedListener = onStateChangedListener;
    }

    public interface OnStateChangedListener {
        void onDetachedFromWindow(int currentPosition);
    }
}
